<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
   <meta name="Author" content="Build">
   <title>Eclipse Platform Core RFC 0001 - Handling Case Variant Collisions</title>
</head>
<body bgcolor="#FFFFFF" >
<div align="right">
  <table border=0 cellspacing=0 cellpadding=2 width="100%">
    <tr> 
		<td align=LEFT valign=TOP colspan="2" bgcolor="#0080C0"><b><font face="Arial,Helvetica"><font color="#FFFFFF">
			Request For Comment
		</font></font></b></td>
    </tr>
  </table>
</div>
<div align="left"> 
  <h1><img src="../images/idea.gif" width="120" height="86"></h1>
</div>
<h1 align="CENTER">Eclipse Platform Core RFC 0001</h1>
<h1 align="CENTER">Case Variant Collisions During Resource Creation.</h1>
<blockquote> 
  <p><b>Summary</b> <br>
    The Eclipse workspace is always case-sensitive, but some filesystems are not.  This causes
    a problem when trying to create a file using the Core API, in the case where
    a file already exists at the target location that differs only in case from the file being created.
    This document discusses the problem and evaluates various approaches to solving it.
  <p><b>By John Arthorne, OTI.</b> <br>
    <font size="-1">Created: November 26, 2001</font> <br>
    <font size="-1">Last Modified: January 4, 2002</font> <br>
</blockquote>
<hr>
<h2>The Problem</h2>
Let us define three resource handles:
<pre>
	IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("Project");
	IFile abc = project.getFile("abc.txt");
	IFile ABC = project.getFile("ABC.txt");
</pre>
The initial state of the problem is when <tt>project</tt> and <tt>abc</tt> already exist.
If a Core API method is used to create <tt>ABC</tt> (using either <tt>create</tt>, <tt>copy</tt>, 
or <tt>move</tt> API methods), an exception is thrown.  The exception 
detail states that the file could not be created because it already exists. The contradiction 
is that <tt>ABC.exists()</tt>will return false, since the case sensitive workspace does not 
recognize the collision with <tt>abc</tt>.  Likewise, lookup methods such as 
<tt>project.findMember("ABC.txt")</tt> will also fail to locate the existing file <tt>abc</tt>,
leading the API user to believe that it is ok to go ahead and create <tt>ABC</tt>.
</p>
<p>
Note that this is not quite the same as when a case variant already exists in the file system,
but not in the workspace.  Following the above example, say a local file "abc.txt" does not
exist in the workspace, but is created externally in the filesystem.  In this case, the current
behaviour when a client calls <tt>ABC.create()</tt> is consistent; it throws an exception 
stating that the workspace is out of sync with the local filesystem.
</p>
<p>
<font color="#F00D1E">New comment:
It should be noted that this problem arises from the fact that the platform case sensitivity
does not always match the case sensitivity of the underlying filesystem.  In most cases,
this inconsistency can be handled by the platform core without requiring special handling
by callers of core API.  However, this situation represents one rare corner case that cannot be 
resolved silently.  This is because "under the covers" resolution would require core to 
delete files from the filesystem without user awareness.</font>
</p>
<h2>Proposed Solution</h2>
The proposal is to add a new core status code, IResourceStatus.CASE_VARIANT_EXISTS.
This status code would be included in exceptions from all <tt>create</tt>, <tt>copy</tt>, 
or <tt>move</tt> API methods in the IResource hierarchy, when a case variant already exists 
at the target location.  The exception will also include an appropriate error message 
describing why the creation couldn't continue.
<ul><b>Pros:</b>
<li>This solution allows clients to recognize the situation and act accordingly.  Core cannot determine
the appropriate behaviour for all cases when this problem occurs, so the decision must
be left to the caller.  For example, say a resource "/Project/abc/myfile.txt" already exists.
A client wants to create a file called "/Project/ABC/anotherfile.txt".  When they attempt to
create folder ABC, a failure occurs because of the case variant collision.  In this situation,
the caller may know that the case of the folder isn't important, and they'll just go ahead and create
"/Project/abc/anotherfile.txt".  In another situation, the caller may decide it is better
to delete the existing "abc" folder, and create the new "ABC" folder in its place. In a third situation,
the client may decide to defer the question to the user.</li>
<li>Minimal impact on downstream clients.  This fix requires no breaking API changes, and the 
new behaviour is similar to the old behaviour.  In both new and old approaches, an exception is 
thrown -- the only thing that has changed is the status code.</li>
</ul>
<ul><b>Cons:</b>
<li>Status codes are fuzzy API.  API methods do not formally guarantee what status
codes will be returned for a given error condition.  The status codes could theoretically
change at any time without warnings or deprecations.</li>
<font color="#F00D1E">New comment: while the status codes returned by a particular
method are technically fuzzy, we strive to avoid changing return status codes without a 
very compelling reason and sufficient advance notice.  The code constant and value are API
and will not change.</font>
<li><font color="#0000FF">Feedback: There is still an inconsistency between the behaviour 
of exists and create.</font></li>
</ul>
<font color="#0000FF">Feedback: Each project can be associated with a different repository 
and the versioning abilities of that project are governed by the target repository (adapter). 
It seems strange that we would not argue that a project's case sensitive behavior wouldn't 
be based on the target file system it was stored on.</font>
</p><p>
<font color="#F00D1E">Response: Yes, you could argue that this approach would give a more
consistent user experience.  However, this would unfortunately require a radical redesign 
and a major overhaul of large amounts of platform code.  What this solution proposes
is the best we could come up with under the constraints of the existing architecture.</font>
</p>
<h2>Alternative Solutions</h2>
This section describes proposed alternative solutions, and some comments on them. 
More alternative solutions will be added as they are raised during discussion.  Please
feel free to add to or dispute any pros and cons already listed.
<h3>Make the Workspace Case-Sensitivity Match the Filesystem</h3>
With this approach, when the Eclipse workspace is run on a case-insensitive operating
system, the workspace would never be case-sensitive.  On case-sensitive operating
systems, the workspace would always be case-sensitive.
<ul><b>Pros:</b>
<li>Behaviour is consistent with the underlying filesystem</li>
<li>Core API methods are always consistent with each other.  If there is a failure
to create because the target already exists, then <tt>exists</tt> and <tt> findMember</tt>
methods will also find the target in all cases.</li>
</ul>
<ul><b>Cons:</b>
<li>Performance.  This approach would have a huge performance cost.  The critical
performance path for the workspace is lookups in the resource tree.  This lookup
is based on a high performance binary search in the resource tree.  This search cannot
be performed as efficiently when ignoring case.</li>
<li>Inconsistency gets pushed up to higher layers.  In many cases this approach
merely moves the file-system inconsistency problems up to other plugins.  Callers of 
Core API can currently rely on it always being case-sensitive, and can act accordingly.
Core is able to handle some of these inconsistent situations without involving client
plug-ins.</li>
<font color="#0000FF">Feedback: You could argue that providing a case sensitive workspace 
in the absence of a case sensitive file system is also pushing up an inconsistency to layers 
above that may also need to deal with external tools?</font>
<li>Inconsistencies still possible when workspace spans filesystems.  If the
user has a workspace where some projects are mounted on a case-sensitive
filesystem, and others are mounted on a case-insensitive filesystem, there would still be
an inconsistency.  Such a setup would undoubtedly cause widespread problems for
downstream plug-ins trying to manage such an inconsistent workspace.</li>
</ul>
<h2>Related Bugs:</h2>
<ul>
<li><a href="http://dev.eclipse.org/bugs/show_bug.cgi?id=3140">3140: Ignored case</a></li>
<li><a href="http://dev.eclipse.org/bugs/show_bug.cgi?id=3076">3076: Can't import com and COM</a></li>
</ul>
<h2>RFC Status</h2>
<p>This proposal is has been voted on and accepted.
</p>
</body>
</html>